package com.seguriapp.crimeactivity.gwt.client;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.google.gwt.core.client.Callback;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.geolocation.client.Geolocation;
import com.google.gwt.geolocation.client.Position;
import com.google.gwt.geolocation.client.PositionError;
import com.google.gwt.maps.client.InfoWindow;
import com.google.gwt.maps.client.InfoWindowContent;
import com.google.gwt.maps.client.MapOptions;
import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.control.SmallMapControl;
import com.google.gwt.maps.client.event.MarkerClickHandler;
import com.google.gwt.maps.client.geocode.Geocoder;
import com.google.gwt.maps.client.geocode.LatLngCallback;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.maps.client.geom.Size;
import com.google.gwt.maps.client.overlay.Marker;
import com.google.gwt.maps.utility.client.DefaultPackage;
import com.google.gwt.maps.utility.client.GoogleMapsUtility;
import com.google.gwt.maps.utility.client.markerclusterer.MarkerClusterer;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HTMLPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.seguriapp.crimeactivity.gwt.client.activity.CrimeActivityActivity;
import com.seguriapp.crimeactivity.gwt.client.activity.CrimeActivityActivity.Display;
import com.seguriapp.entities.Complaint;
import com.seguriapp.entities.CrimeCategory;

public class CrimeActivityPage extends Composite implements Display {

  private static final Logger LOG = Logger.getLogger(CrimeActivityPage.class.getName());

  private static CrimeActivityPageUiBinder uiBinder = GWT.create(CrimeActivityPageUiBinder.class);

  interface CrimeActivityPageUiBinder extends UiBinder<Widget, CrimeActivityPage> {
  }

  @UiField
  protected HTMLPanel mapPanel;
  @UiField
  protected HTMLPanel mapOptions;
  @UiField
  protected TextBox gotoTextBox;

  private MapWidget map;
  private final ClickHandler mapOptionsHandler;

  private CrimeActivityActivity presenter;

  public CrimeActivityPage() {
    initWidget(uiBinder.createAndBindUi(this));
    mapOptionsHandler = new ClickHandler() {

      public void onClick(final ClickEvent event) {
        updateMapData();
      }

    };
  }

  @UiHandler("gotoButton")
  protected void onGoToButtonClick(final ClickEvent event) {
    if (gotoTextBox.getText() != null && !gotoTextBox.getText().isEmpty()) {
      gotoPlace(gotoTextBox.getText());
    }
  }

  public void setPresenter(final CrimeActivityActivity presenter) {
    this.presenter = presenter;
  }

  public void setMapData(final List<Complaint> list, final double defaultLat, final double defaultLng, final int zoomValue, final String mapOptionsStr, final boolean getUserLocation) {

    final MapOptions mapOptions = MapOptions.newInstance();
    mapOptions.setSize(Size.newInstance(800, 400));

    if (map == null) {
      map = new MapWidget(LatLng.newInstance(defaultLat, defaultLng), zoomValue, mapOptions);
    } else {
      map = new MapWidget(map.getCenter(), map.getZoomLevel(), mapOptions);
    }

    map.setScrollWheelZoomEnabled(true);
    map.addControl(new SmallMapControl());

    if (getUserLocation) {
      getUserLocation();
    }
    mapPanel.clear();
    mapPanel.add(map);

    setMapOptionsValuesFromResponse(mapOptionsStr);
    setMarkerClustered(list);
  }

  public void setCrimeCategoryList(final List<CrimeCategory> crimeCategoryList) {
    mapOptions.clear();
    for (final CrimeCategory crimeCategory : crimeCategoryList) {
      final CheckBox checkBox = new CheckBox(crimeCategory.getName());
      checkBox.setFormValue(crimeCategory.getId().toString());
      checkBox.addClickHandler(mapOptionsHandler);
      mapOptions.add(checkBox);
    }
  }

  private void setMapOptionsValuesFromResponse(final String mapOptionsStr) {
    String [] mapOptionsArray = mapOptionsStr.split(",");
    for (int i = 0; i < mapOptions.getWidgetCount(); i++) {
      final CheckBox checkbox = (CheckBox) mapOptions.getWidget(i);
      checkbox.setValue(false);
      for (final String optionId : mapOptionsArray) {
        if (checkbox.getFormValue().equals(optionId)){
          checkbox.setValue(true);
          break;
        }
      }
    }
  }

  private void gotoPlace(final String address) {
    final Geocoder geocoder = new Geocoder();
    geocoder.getLatLng(address, new LatLngCallback() {

      public void onFailure() {
        Window.alert(address + " no encontrado");
      }

      public void onSuccess(final LatLng point) {
        map.setCenter(point, 13);
      }
    });
  }

  private String getMarketDescription(final Complaint complaint) {
    return complaint.getCategory().getName();
  }

  private void getUserLocation() {
    final Geolocation geolocation = Geolocation.getIfSupported();
    geolocation.getCurrentPosition(new Callback<Position, PositionError>() {

      public void onSuccess(Position result) {
        map.setCenter(LatLng.newInstance(result.getCoordinates().getLatitude(), result.getCoordinates().getLongitude()));
      }

      public void onFailure(PositionError reason) {
        LOG.log(Level.SEVERE, "Error setting map center", reason);
      }
    });
  }

  private void updateMapData() {
    String options = "";
    for (int i = 0; i < mapOptions.getWidgetCount(); i++) {
      final CheckBox checkbox = (CheckBox) mapOptions.getWidget(i);
      if (checkbox.getValue()) {
        options = options.concat(checkbox.getFormValue()).concat(",");
      }
    }
    if (!options.isEmpty()) {
      options = options.substring(0, options.length() - 1);
    }
    presenter.updateMapData(options);
  }

  private void setMarkerClustered(final List<Complaint> list) {
    if (list != null) {
      if (!GoogleMapsUtility.isLoaded(DefaultPackage.MARKER_CLUSTERER)) {
        GoogleMapsUtility.loadUtilityApi(new Runnable() {
          public void run() {
            loadSampleData(list);
          }
        }, DefaultPackage.MARKER_CLUSTERER);
      } else {
        loadSampleData(list);
      }
    }
  }

  private void loadSampleData(final List<Complaint> list) {
    final Marker[] markers = new Marker[list.size()];
    int i = 0;
    for (final Complaint complaint : list) {
      final LatLng latlng = LatLng.newInstance(complaint.getCrimeLatitude(), complaint.getCrimeLongitude());
      // MarkerOptions opts = MarkerOptions.newInstance(Icon.newInstance(icon));
      final Marker marker = new Marker(latlng);
      marker.addMarkerClickHandler(new MarkerClickHandler() {

        public void onClick(MarkerClickEvent event) {
          InfoWindow info = map.getInfoWindow();
          info.open(event.getSender(), new InfoWindowContent("<span class='mapInfoText'>" + getMarketDescription(complaint) + "</span>"));
        }
      });
      markers[i] = marker;
      i++;
    }
    MarkerClusterer.newInstance(map, markers);
  }

}
